package com.example.gbuffer.Utils;

import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ConfigurationInfo;
import android.opengl.GLES32;
import android.util.Log;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;

public class OpenGLUtils {

    private static final String LOG_TAG = "OpenGLUtils";
    /**
     * @brief 获取当前绑定的framebuffer
     * @return 当前 framebuffer id
     */
    public static int getCurrentFramebuffer() {
        // 创建一个数组来存储当前 framebuffer ID
        int[] framebuffer = new int[1];

        // 获取当前绑定的 framebuffer ID
        GLES32.glGetIntegerv(GLES32.GL_FRAMEBUFFER_BINDING, framebuffer, 0);

        // 返回当前 framebuffer ID
        return framebuffer[0];
    }

    /**
     * @brief 检查是否支持opengl es 320
     * @param activity 当前活动
     * @return 是否支持
     */
    public static boolean isOpenGLES32Supported(Activity activity) {
        ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
        ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
        return (configurationInfo.reqGlEsVersion >= 0x00030002); // OpenGL ES 3.2 version is 0x00030002
    }

    /**
     * @brief 检查当前 framebuffer 的完整性
     * @return true: 完整； false：不完整
     */
    public static boolean checkFramebufferStatus() {

        // 检查 framebuffer 状态
        int status = GLES32.glCheckFramebufferStatus(GLES32.GL_FRAMEBUFFER);

        // 根据返回的状态值判断完整性
        switch (status) {
            case GLES32.GL_FRAMEBUFFER_COMPLETE:
                return true; // 完整

            case GLES32.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
                Log.e(LOG_TAG, "Framebuffer incomplete: Attachment is not complete.");
                break;

            case GLES32.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
                Log.e(LOG_TAG, "Framebuffer incomplete: No attachments.");
                break;

            case GLES32.GL_FRAMEBUFFER_UNSUPPORTED:
                Log.e(LOG_TAG, "Framebuffer incomplete: Unsupported format.");
                break;

            default:
                Log.e(LOG_TAG, "Framebuffer incomplete: Unknown error.");
                break;
        }

        return false; // 不完整
    }

    public static int checkMaxFragmentUniformVectors() {
        // 查询最大片段 uniform 向量数量
        int[] maxFragmentUniformVectors = new int[1];
        GLES32.glGetIntegerv(GLES32.GL_MAX_FRAGMENT_UNIFORM_VECTORS, maxFragmentUniformVectors, 0);

        return maxFragmentUniformVectors[0];
    }

    /**
     * @brief 创建一个Texture2D类型的的RGBA纹理。Texture2D内部格式为GL_RGBA，
     * @param width 纹理的宽度（像素）
     * @param height 纹理的高度（像素）
     * @param r 红色通道值（0.0~1.0）
     * @param g 绿色通道值（0.0~1.0）
     * @param b 蓝色通道值（0.0~1.0）
     * @param a Alpha通道值（0.0~1.0）
     * @return Texture ID
     */
    public static int generateTextureRGBA(int width, int height, float r, float g, float b ,float a) {
        // 1. 创建 ByteBuffer 并填充白色数据 (RGBA = {1.0, 1.0, 1.0, 1.0})
        int pixelSize = 4; // RGBA, so 4 bytes per pixel
        ByteBuffer buffer = ByteBuffer.allocateDirect(width * height * pixelSize * 4)
                .order(ByteOrder.nativeOrder());

        for (int i = 0; i < width * height; i++) {
            // 填充白色 (RGBA = {255, 255, 255, 255})，OpenGL 中颜色值范围是 [0, 1]，所以需要除以 255.0f
            buffer.putFloat(r); // R
            buffer.putFloat(g); // G
            buffer.putFloat(b); // B
            buffer.putFloat(a); // A
        }
        buffer.rewind(); // 准备读取数据

        // 2. 生成纹理
        int[] textureIds = new int[1];
        GLES32.glGenTextures(1, textureIds, 0);

        int textureId = textureIds[0];
        GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, textureId);

        // 3. 配置纹理参数
        GLES32.glTexParameterf(GLES32.GL_TEXTURE_2D, GLES32.GL_TEXTURE_MIN_FILTER, GLES32.GL_LINEAR);
        GLES32.glTexParameterf(GLES32.GL_TEXTURE_2D, GLES32.GL_TEXTURE_MAG_FILTER, GLES32.GL_LINEAR);
        GLES32.glTexParameteri(GLES32.GL_TEXTURE_2D, GLES32.GL_TEXTURE_WRAP_S, GLES32.GL_CLAMP_TO_EDGE);
        GLES32.glTexParameteri(GLES32.GL_TEXTURE_2D, GLES32.GL_TEXTURE_WRAP_T, GLES32.GL_CLAMP_TO_EDGE);

        // 4. 上传数据到纹理
        GLES32.glTexImage2D(GLES32.GL_TEXTURE_2D, 0, GLES32.GL_RGBA, width, height, 0,
                GLES32.GL_RGBA, GLES32.GL_FLOAT, buffer);

        // 解绑纹理
        GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, 0);

        return textureId;
    }

    /**
     * @brief 将深度缓冲从一源帧缓冲复制到目标帧缓冲
     * @param srcFboId 源帧缓冲的id
     * @param srcRect 源帧缓冲的复制矩形区域，坐标系原点在屏幕左下角，x轴向右，y轴向上
     * @param dstFboId 目标帧缓冲的id
     * @param dstRect 同理
     */
    public static void copyDepthBufferBetweenFramebuffer(int srcFboId, GLViewportRect srcRect, int dstFboId, GLViewportRect dstRect) {

        IntBuffer currentFbo = IntBuffer.wrap(new int[1]);
        currentFbo.position(0);
        GLES32.glGetIntegerv(GLES32.GL_FRAMEBUFFER_BINDING, currentFbo);

        GLES32.glBindFramebuffer(GLES32.GL_READ_FRAMEBUFFER, srcFboId);
        int readStatus = GLES32.glCheckFramebufferStatus(GLES32.GL_FRAMEBUFFER);
        if (readStatus != GLES32.GL_FRAMEBUFFER_COMPLETE) {
            Log.e(LOG_TAG, "Read framebuffer not complete: " + readStatus);
        }

        GLES32.glBindFramebuffer(GLES32.GL_DRAW_FRAMEBUFFER, dstFboId);
        int drawStatus = GLES32.glCheckFramebufferStatus(GLES32.GL_FRAMEBUFFER);
        if (drawStatus != GLES32.GL_FRAMEBUFFER_COMPLETE) {
            Log.e(LOG_TAG, "Draw framebuffer not complete: " + drawStatus);
        }

        GLES32.glBindFramebuffer(GLES32.GL_READ_FRAMEBUFFER, srcFboId);
        GLES32.glBindFramebuffer(GLES32.GL_DRAW_FRAMEBUFFER, dstFboId);

        OpenGLUtils.clearOpenGLError();
        GLES32.glBlitFramebuffer(
                srcRect.x(), srcRect.y(), srcRect.x() + srcRect.width(), srcRect.y() + srcRect.height(),
                dstRect.x(), dstRect.y(), dstRect.x() + dstRect.width(), dstRect.y() + dstRect.height(),
                GLES32.GL_DEPTH_BUFFER_BIT, GLES32.GL_NEAREST
        );
        OpenGLUtils.logOpenGLError();

        GLES32.glBindFramebuffer(GLES32.GL_FRAMEBUFFER, currentFbo.get(0));
    }

    public static void clearOpenGLError() {
        while(GLES32.glGetError() != GLES32.GL_NO_ERROR);
    }

    public static void logOpenGLError() {
        int error;
        while ((error = GLES32.glGetError()) != GLES32.GL_NO_ERROR) {
            switch (error) {
                case GLES32.GL_INVALID_ENUM:
                    Log.e(LOG_TAG, "GL_INVALID_ENUM");
                    break;
                case GLES32.GL_INVALID_VALUE:
                    Log.e(LOG_TAG, "GL_INVALID_VALUE");
                    break;
                case GLES32.GL_INVALID_OPERATION:
                    Log.e(LOG_TAG, "GL_INVALID_OPERATION");
                    break;
                case GLES32.GL_OUT_OF_MEMORY:
                    Log.e(LOG_TAG, "GL_OUT_OF_MEMORY");
                    break;
                default:
                    Log.e(LOG_TAG, "Unknown error: " + error);
                    break;
            }
        }
    }

}